package org.otherworld.interpreter;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import org.otherworld.process.SystemInfoUtils;
import org.otherworld.property.PropertyLoader;

public class Interpreter {

	PropertyLoader loader;
	Hashtable<String, Object> messages;
	private static ArrayList<String> mainCommand;

	private ArrayList<String> commands = new ArrayList<String>(); 		// Ebbe fogjuk feltölteni a parancsokat
	private ArrayList<String> connectors = new ArrayList<String>();	 	// Ebbe fogjuk feltölteni a csatolókat
	private String[] availableCommands = { "exit", "log", "search",
			"authenticate", "display" }; 								// Parancsok listája, melyet csak ki kell egészíteni új parancsokkal
	private String[] availableConnectors = { "in", "at", "on", "for" };	// Csatolók listája, melyet csak ki kell egészíteni új csatolókkal	

	String[] tempCommands;												// A Stringként kapott parancsot ebbe a tömbbe dobjuk szét.
	String firstCommand;												// A fő parancs, melyre később hivatkozunk.

	/**
	 * Konstruktor osztály. Itt töltjük fel a commands és a connectors ArrayListeket, ahonnan a továbbiakban
	 * vizsgáljuk, hogy egy adott parancs benne van-e a már ismert listában.
	 * 
	 * Ezenkívül betölti a properties osztályt.
	 * 
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	
	public Interpreter() throws FileNotFoundException, IOException {
		loader = new PropertyLoader();
		messages = loader.getProperties();

		for (String s : availableCommands) {
			commands.add(s);
		}

		for (String s : availableConnectors) {
			connectors.add(s);
		}

	}
	
	/**
	 * Fő metódus, amely az értelmezést végrehajta. Egy szövegre van szüksége, amit szétbombáz, megnézi hogy megfelel-e a követelményeknek,
	 * és eszerint értelmezi és végrehajtja.
	 * 
	 * @param command String típus.
	 */

	public void interpret(String command) {
		if (validCommand(command)) {											// Megvizsgálja, hogy a parancs amit kapott egyáltalán deklarálva van-e.
			// System.out.println("Building structure");
			mainCommand = buildCommandStructure(command);						// Feltölt egy ArrayList<String> típust, amivel tud dolgozni.
			String[] firstLine = mainCommand.get(0).toLowerCase().split(" ");	// Az első sort leszedi az ArrayList-ből, ami a parancsot és a paraméterét tartalmazza.

			if (firstCommand.equals("exit") && firstLine.length == 1) {			// Rávizsgál arra, hogy kilépési parancsot kapott-e. Ha igen, intézkedik.
				System.out.println("You are now leaving Tasker. Good bye");
				System.exit(1);
			} else if (firstCommand.equals("exit") && firstLine.length > 1) {	// Rávizsgál arra, hogy kilépéshez kapott-e több paramétert. ha igen, kiírja hogy nem úgy kell.
				System.out
						.println("You only need to write \' exit \' to leave the program.");
			} else if (firstCommand.equals("display")) {						// Display parancs. Gyakorlatilag arra jó, hogy információkat kérjünk le.
				SystemInfoUtils sysinfo = new SystemInfoUtils();
				if (firstLine.length > 2
						&& (firstLine[2].equals("info") || firstLine[2]			
								.equals("information"))) {						// Szükségesen előírja, hogy az info, vagy information szót odaírjuk második paraméternek.

					if (firstLine[1].equals("system")) {				
						sysinfo.displayFullSystemInformation();					// Ha a systemről szeretnék információt, meghívja a displayFullSystemInformation() metódust.
					} else if (firstLine[1].equals("memory")) {
						sysinfo.displayMemoryInformation();						// Ha csak a memóriáról szeretnék információkat, meghívja a displayMemoryInformation() metódust.
										// TODO a többi kisebb modult is megírni
					} else {
						System.out
								.println("Unable to comply; Can not find any information about " + firstLine[1]); // Amennyiben olyan paramétert kap, amit nem tud értelmezni, ezt az üzenetet dobja.
					}

				} else {
					System.out
							.println("Correct usage of the command \' display \' is: \" display something info \""); // Ha a display parancsot helytelenül használják, például kevesebb vagy több paraméterrel.
				}
			} else {
				System.out
						.println("Command not yet finished. Coming soon.");			// Ezt akkor dobja, ha olyan parancsot kérünk, ami még nincs beprogramozva, de a listában szerepel.
			}

		} else {
			System.out
					.println("Command could not be interpreted. You probably typed something wrong.");			// Ezt akkor dobja, ha a parancs szintaktikája helytelen.
		}
	}

	
	/**
	 * Eldönti, hogy a kapott parancs megfelel-e az elvárásoknak - olyan szóval kezdődik, amit már ismerünk, és működőképes.
	 * @param command
	 * @return true or false
	 */
	private boolean validCommand(String command) {
		tempCommands = command.split(" ");
		
		firstCommand = tempCommands[0].toLowerCase();
		if (commands.contains(tempCommands[0])) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * A Stringként kapott parancsot szétdobja, és egy többdimenziós tömbbe tölti.
	 * 
	 * Az első sor maga a parancs és a következő csatolóig tartó paraméterek
	 * A második és további sorok mindig egy csatolóval kezdődnek és a következő csatolóig tartanak.
	 * 
	 * @param command String - parancs.
	 * @return ArrayList<String> - a feltöltött tömb
	 */
	
	
	private ArrayList<String> buildCommandStructure(String command) {
		ArrayList<String> tempArray = new ArrayList<String>();
		String temp = "";
		int counter = 0;

		for (int i = 0; i < tempCommands.length; ++i) {
			
			if (connectors.contains(tempCommands[i])){
				tempArray.add(temp);
				System.out.println(temp);
				temp = "";
				counter++;
			}
			temp += tempCommands[i]+ " ";
		}
		if (counter == 0) {
			tempArray.add(command);
		}
		
		return tempArray;
	
	}
}
